package com.wf.day_0619.test2;

import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Author fengqq
 * @Description 模拟 IOC中 注解的配置
 * @Date 2024/6/19  14:22
 */
public class ApplicationContext {

    private static Map<String,Object> map = new LinkedHashMap<>();

    //1.判断指定的类型是否带有@MyController注解，如果有则将指定类型的实例 保存到map集合中
    //2.如果指定的类型是否带有@MyController注解的前提下，查看的属性上是否有@MyValue注解 完成对属性值的赋值工作 ==>依赖注入
    //3.如果指定的类型是否带有@MyController注解的前提下， 查看的属性上是否有@MyAutowired注解 完成对属性值的赋值工作 ==>自动装配
    public static void loadClass(Class<?> type){
        try{
            // 检查类型是否被@MyController注解标记
            //1.判断指定的类型是否带有@MyController注解
            if(type.isAnnotationPresent(MyController.class)){
                // 获取@MyController注解实例
                //2.获取@MyController注解 以及属性的取值
                MyController myController = type.getDeclaredAnnotation(MyController.class);
                // 从注解中获取beanName
                String key = myController.beanName();
                // 实例化类型
                Object object = type.newInstance();
                // 遍历类型的所有字段
                for (Field field : type.getDeclaredFields()) {
                    // 检查字段是否被@MyValue注解标记
                    if(field.isAnnotationPresent(MyValue.class))
                    {
                        // 获取@MyValue注解实例
                        MyValue myValue = field.getDeclaredAnnotation(MyValue.class);
                        // 从注解中获取字段值
                        String value = myValue.value();
                        // 设置字段可访问
                        field.setAccessible(true);
                        // 获取字段类型
                        Class<?> fieldType = field.getType();
                        // 根据字段类型设置字段值
                        if(fieldType == String.class){
                            field.set(object,value);
                        }else if(fieldType == int.class){
                            field.set(object,Integer.parseInt(value));
                        }else if(fieldType == long.class){
                            field.set(object,Long.parseLong(value));
                        }else if(fieldType == double.class){
                            field.set(object,Double.parseDouble(value));
                        }else if(fieldType == float.class){
                            field.set(object,Float.parseFloat(value));
                        }else
                        {
                            System.out.println("不支持的类型!!!");
                        }
                    }
                    // 检查字段是否被@MyAutowired注解标记
                    else if(field.isAnnotationPresent(MyAutowired.class))
                    {
                        // 获取@MyAutowired注解实例
                        MyAutowired myAutowired = field.getDeclaredAnnotation(MyAutowired.class);
                        // 从注解中获取beanName
                        String s = myAutowired.beanName();
                        // 检查map中是否包含对应的bean
                        if(map.containsKey(s)){
                            // 设置字段可访问
                            field.setAccessible(true);
                            // 设置字段值为map中对应的bean
                            field.set(object,map.get(s));
                        }else{
                            System.out.println("没有找到名字为"+s+"的bean");
                        }
                    }
                }
                // 将实例添加到map中，以beanName为键
                //3.以beanName作为key 以当前类型的实例作为value  保存到map集合中
                map.put(key,object);
            }else{
                System.out.println(type.getName()+"上面没有@MyController注解");
            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    //从ApplicationContext容器中 根据key来获取对应的实例
    public static <T> T getBean(String key,Class<T> type){
        if(map.containsKey(key)){
            return (T)(map.get(key));
        }
        return null;
    }

    public static void main(String[] args) {
        ApplicationContext.loadClass(Person.class);

        ApplicationContext.loadClass(Teacher.class);

        System.out.println("-----------------------------------");
        Person person = ApplicationContext.getBean("p1", Person.class);
        System.out.println(person);

        Teacher teacher = ApplicationContext.getBean("teacher", Teacher.class);
        System.out.println(teacher);
    }

}
